package vo_reflect3;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;

public class BeanOperation {

    private BeanOperation(){

    }

    /**
     * 负责设置类中的属性操作
     * @param actionObject 当前发出请求的程序类的当前对象
     * @param msg   属性的具体内容，格式为： "属性名称:内容|属性名称:内容|......"
     */
    public static void setBeanValue(Object actionObject,String msg)throws Exception{
        //对msg进行字符串拆分
        String[] data = msg.split("\\|");
        for (int i=0;i<data.length;i++){
            String[] temp = data[i].split(":");

            //属性名称"emp.ename"
            String attribute = temp[0];
            //属性内容

            String[] feilds = attribute.split("\\.");

            //通过对属性attribute的拆分就可以区分出vo是单级还是多级
            if (feilds.length>2){
                //多级vo操作
                /*
                    String value = "emp.ename:yuisama|emp.job:Java Coder|emp.dept.name:教务
                                    部|emp.dept.company.cname=bit" ;
                    要对这样一个value进行操作，可以看到多级vo。
                    如果要想通过多级确定出属性的操作对象，那么就应该一层层找出每一个getter方法返回的内容
                 */
                Object currentObject = actionObject;
                for (int j=0;j< feilds.length-1;j++){
                    //对应的getter的返回对象
                    //循环结束后一定能拿到最后一层的当前对象。
                    currentObject = getObject(currentObject, feilds[j]);
                }

                Object value = getValue(currentObject, feilds[feilds.length - 1], temp[1]);
                setObjectValue(currentObject,feilds[feilds.length-1],value);

            }else {
                //获取当前操作的简单java类对象
                Object value = getValue(actionObject, attribute, temp[1]);
                Object currentObject = getObject(actionObject, feilds[0]);
                setObjectValue(currentObject, feilds[1], value);
            }

        }
    }

    /**
     * 将给定字符串大写
     * @param str   给定的字符串
     * @return  返回首字母大写的字符串
     */
    public static String initCap(String str){
        return str.substring(0,1).toUpperCase()+str.substring(1);
    }

    /**
     *  负责调用XXXAction中的getter方法取得简单的java类对象
     * @param obj   调用方法所在的类
     * @param attribute   属性名称
     * @return  对象结果
     */
    public static Object getObject(Object obj,String attribute)throws Exception{
        String methodName = "get"+initCap(attribute);
        Field field = obj.getClass().getDeclaredField(attribute);
        if (field==null){
            //如果第一次没找到该属性，那么在进行一次查找
            field = obj.getClass().getDeclaredField(attribute);
        }
        if (field==null){
            //两次都没找到该属性，则此属性一定不存在，返回值为空
            return null;
        }
        //找到其get方法，并返回
        Method method = obj.getClass().getMethod(methodName);
        return method.invoke(obj);
    }

    /**
     *  根据指定类对象设置指定类中的属性，调用其setter方法
     * @param obj   属性所在类的实例化对象
     * @param attribute 属性名称
     * @param value 属性内容
     */
    public static void setObjectValue(Object obj,String attribute,Object value)throws Exception{
        Field field = obj.getClass().getDeclaredField(attribute);
        if (field==null){
            field = obj.getClass().getDeclaredField(attribute);
        }
        if (field==null){
            return;
        }
        String methodName = "set"+initCap(attribute);
        Method method = obj.getClass().getMethod(methodName, field.getType());
        method.invoke(obj,value);
    }

    /**
     * 将字符串的内容根据属性类型变为各种数据类型
     * 支持的类型有:int(Integer)  double(Double)  long(Long)  String  Date
     * @param wrapObject    包装类
     * @param attribute     属性
     * @param value      属性值
     * @return      根据属性类型进行转型处理
     */
    public static Object getValue(Object wrapObject,String attribute,String value)throws Exception{
        Field field = wrapObject.getClass().getDeclaredField(attribute);
        if (field==null){
            field = wrapObject.getClass().getDeclaredField(attribute);
        }
        if (field==null){
            return null;
        }
        return stringToType(field.getType().getSimpleName(),value);
    }

    /**
     * 根据指定类型将字符串进行转换处理
     * @param type  数据类型
     * @param value 数据内容
     * @return  转换为具体类型
     */
    private static Object stringToType(String type,String value)throws Exception{
        if ("String".equals(type)){
            if (isNotNull(value)){
                return value;
            }else {
                return null;
            }
        }else if ("int".equals(type)||"Integer".equals(type)){
            if (isInt(type)) {
                return Integer.parseInt(value);
            }
        }else if ("double".equals(type)||"Double".equals(type)){
            if (isDouble(type)){
                return Double.parseDouble(value);
            }
        }else if ("long".equals(type)||"Long".equals(type)){
            if (isDouble(type)){
                return Double.parseDouble(value);
            }
        }else if ("Date".equals(type)){
            String pattern = null;
            if (isDate(type)){
                pattern =  "yyyy-MM-dd";
            }
            if (pattern!=null){
                return new SimpleDateFormat(pattern).parse(value);
            }
        }
        return null;
    }

    /**
     * 判断字符串是否为空
     * @param str  要判断的字符串
     * @return  如果为空返回false 否则返回true
     */
    private static boolean isNotNull(String str){
        return !(str == null || str.isEmpty());
    }

    /**
     * 判断给定字符串是否为一个整数
     * @param str  给定字符串
     * @return  由整数组成，返回true，否则返回false
     */
    private static boolean isInt(String str){
        if (isNotNull(str)){
            return str.matches("\\d+");
        }
        return false;
    }

    /**
     * 判断给定字符串是否是一个小数
     * @param str  给定字符串
     * @return  小数返回true，否则返回false
     */
    private static boolean isDouble(String str){
        if (isNotNull(str)){
            return str.matches("\\d+(\\.\\d+)?");
        }
        return false;
    }

    /**
     * 判断给定字符串是否是一个日期类型(yyyy -MM -dd)
     * @param str
     * @return
     */
    private static boolean isDate(String str){
        if (isNotNull(str)){
            return str.matches("\\d{4}-\\d{2}-\\d{2}") ;
        }
        return false ;
    }



}
